package cn.cdyx.common.aop;

import cn.cdyx.common.annotation.SysLog;
import cn.cdyx.common.pojo.SystemLog;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.LocalDateTime;

/**
 * @Author Watermelon
 * @Date 2023-01-17 18:44
 * 日志切面类
 */
@Aspect
@Component
@Slf4j
public class SysLogAspect {
    @Pointcut("@annotation(cn.cdyx.common.annotation.SysLog)")
    public void logPintCut(){};

    @Around("logPintCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable{
        SysLog sysLog = ((MethodSignature)point.getSignature()).getMethod().getAnnotation(SysLog.class);
        String desc = sysLog.desc();


        ServletRequestAttributes Attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = Attributes.getRequest();

        SystemLog systemLog = new SystemLog();
        String className = point.getTarget().getClass().toString() +"."+ point.getSignature().getName();
        ObjectMapper mapper = new ObjectMapper();
        String param = mapper.writeValueAsString(point.getArgs());

        LocalDateTime beginTime = LocalDateTime.now();
        Object proceed = point.proceed();
        LocalDateTime endTime = LocalDateTime.now();

        MethodSignature signature = (MethodSignature)point.getSignature();
        Method method = signature.getMethod();
        String url = request.getRequestURI().toString();

        systemLog.setDescription(desc);
        systemLog.setIp(getRemoteHost(request));
        systemLog.setSysMethod(className);
        systemLog.setMethod(request.getMethod());
        systemLog.setParameter(param);
        systemLog.setResult(proceed);
        systemLog.setSpendTime(Duration.between(beginTime,endTime).toMillis());
        systemLog.setStartTime(beginTime);
        systemLog.setUri(request.getRequestURI());
        systemLog.setUrl(request.getRequestURL().toString());
        log.info("方法日志：{}", systemLog);
        return proceed;
    }

    /**
     * 获取请求参数
     * @param joinPoint
     * @param request
     * @return
     * @throws JsonProcessingException
     */
    private String getParameter(ProceedingJoinPoint joinPoint,HttpServletRequest request) throws JsonProcessingException {

        String reqParam = "";
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method targetMethod = methodSignature.getMethod();
        Annotation[] annotations = targetMethod.getAnnotations();
        for (Annotation annotation : annotations) {
            //此处可以改成自定义的注解
            if (annotation.annotationType().equals(RequestMapping.class)) {
                reqParam = new ObjectMapper().writeValueAsString(request.getParameterMap());
                break;
            }
        }
        return reqParam;
    }

    /**
     * 获取IP
     * @param request
     * @return
     */
    private String getRemoteHost(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }
}
